﻿using System;
using System.Reflection;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;

namespace XamlInspector.Model
{
    public class XamlProperty : ViewModelBase
    {
        private readonly PropertyInfo _propertyInfo;
        private readonly object _element;
        private readonly FrameworkElement _frameworkElement;
        private readonly DependencyProperty _dependencyProperty;

        public XamlProperty(PropertyInfo propertyInfo, object element, string category = "Common")
        {
            _propertyInfo = propertyInfo;
            _element = element;
            Name = _propertyInfo.Name;
            Type = _propertyInfo.PropertyType;
            IsEditable = propertyInfo.CanWrite;
            Category = category;

            _dependencyProperty = PropertyHelper.GetDependencyProperty(element, propertyInfo);
            _frameworkElement = element as FrameworkElement;

            Refresh();
        }

        public string TextValue
        {
            get
            {
                try
                {
                    if (_propertyInfo.GetIndexParameters().Length > 0)
                    {
                        return string.Format("{0} ({1})", _propertyInfo.DeclaringType.Name, _propertyInfo.GetIndexParameters().Length);
                    }
                    return string.Format("{0}", _propertyInfo.GetValue(_element));
                }
                catch (Exception ex)
                {
                    return ex.Message;
                }
            }
            set
            {
                if (_propertyInfo.CanWrite)
                {
                    _propertyInfo.SetValue(_element, Convert.ChangeType(value, Type));
                }
            }
        }

        public string Description
        {
            get
            {
                BindingExpression binding = null;
                if (_frameworkElement != null && _dependencyProperty != null)
                {
                    binding = _frameworkElement.GetBindingExpression(_dependencyProperty);
                }

                if (binding != null)
                {
                    return BindingHelper.FormatBinding(binding.ParentBinding);
                }

                if (IsLocalValue)
                {
                    return "Local";
                }

                return string.Empty;
            }
        }

        public string Category { get; set; }
        public string Name { get; set; }
        public Type Type { get; set; }
        public bool IsEditable { get; set; }

        public bool IsDataBound
        {
            get
            {
                return _frameworkElement != null && _dependencyProperty != null &&
                       _frameworkElement.GetBindingExpression(_dependencyProperty) != null;
            }
        }

        public bool IsLocalValue
        {
            get
            {
                return _frameworkElement != null && _dependencyProperty != null &&
                       _frameworkElement.ReadLocalValue(_dependencyProperty) != DependencyProperty.UnsetValue;
            }
        }

        protected object Element
        {
            get { return _element; }
        }

        protected PropertyInfo PropertyInfo
        {
            get { return _propertyInfo; }
        }

        public void Refresh()
        {
            Notify("TextValue", "IsLocalValue", "IsDataBound");
        }

        public void Reset()
        {
            if (_frameworkElement != null && _dependencyProperty != null)
            {
                _frameworkElement.ClearValue(_dependencyProperty);
            }
        }
    }
}
